<?php

declare (strict_types=1);

namespace app\store\model\sharp;

use app\store\model\Goods as GoodsModel;
use app\store\model\sharp\GoodsSku as GoodsSkuModel;
use app\store\model\GoodsSpecRel as GoodsSpecRelModel;
use app\store\model\sharp\ActiveGoods as ActiveGoodsModel;
use app\common\model\sharp\Goods as SharpGoodsModel;
use app\common\enum\goods\SpecType as SpecTypeEnum;
use app\common\library\helper;
use cores\exception\BaseException;

/**
 * 整点秒杀-商品模型
 * Class Goods
 * @package app\store\model\sharp
 */
class Goods extends SharpGoodsModel
{
    const EVENT_ADD = 'add';
    const EVENT_EDIT = 'edit';

    /**
     * 获取列表数据
     * @param string $search
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getList(string $search = '')
    {
        // 设置基础查询条件
        $query = $this->setBaseQuery($this->alias, [['goods', 'goods_id']]);
        // 检索查询条件
        !empty($search) && $query->where('goods.goods_name', 'like', "%{$search}%");
        // 获取活动列表
        $list = $query->where("{$this->alias}.is_delete", '=', 0)
            ->order(["{$this->alias}.sort" => 'asc', "{$this->alias}.create_time" => 'desc'])
            ->paginate(15);
        // 设置商品数据
        return !$list->isEmpty() ? $this->setGoodsListData($list, true) : $list;
    }

    /**
     * 获取秒杀商品详情
     * @param int $sharpGoodsId 秒杀商品ID
     * @return Goods|array|null
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getDetail(int $sharpGoodsId)
    {
        // 获取商品记录
        $goodsInfo = static::detail($sharpGoodsId, ['skuList']);
        empty($goodsInfo) && throwError('很抱歉，商品信息不存在');
        // 商品多规格处理
        if ($goodsInfo['spec_type'] == SpecTypeEnum::MULTI) {
            // 秒杀商品SKU填充主商品参数(商品价格、库存数量、商品sku编码)
            $goodsInfo['skuList'] = GoodsSkuModel::getCommonSkuList($goodsInfo['skuList'], $goodsInfo['goods_id']);
            // 商品规格属性列表
            $goodsInfo['specList'] = GoodsSpecRelModel::getSpecList($goodsInfo['goods_id']);
        }
        return $goodsInfo;
    }

    /**
     * 根据商品ID集获取商品列表
     * @param array $goodsIds
     * @param array $param
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getListByIds(array $goodsIds, array $param = [])
    {
        // 获取商品列表数据
        return parent::getListByIds($goodsIds, $param);
    }

    /**
     * 添加秒杀商品
     * @param array $data
     * @return bool
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function add(array $data): bool
    {
        // 验证主商品能否被添加为秒杀商品
        if (!$this->validateGoodsId((int)$data['goods_id'])) {
            return false;
        }
        // 获取主商品基本信息
        $goodsInfo = (new GoodsModel)->getBasic((int)$data['goods_id']);
        // 记录商品ID、规格类型、秒杀价格及库存
        $data['goods_id'] = $goodsInfo['goods_id'];
        $data['spec_type'] = $goodsInfo['spec_type'];
        $data['seckill_price'] = $goodsInfo['goods_price_min'];
        $data['seckill_stock'] = $goodsInfo['stock_total'];
        // 创建秒杀商品数据
        $data = $this->createData($data, self::EVENT_ADD);
        // 事务处理
        $this->transaction(function () use ($data) {
            // 添加商品
            $this->save($data);
            // 更新商品sku信息
            GoodsSkuModel::add((int)$this['sharp_goods_id'], $this['spec_type'], $data['newSkuList']);
        });
        return true;
    }

    /**
     * 编辑商品
     * @param array $data
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function edit(array $data): bool
    {
        // 记录商品ID和规格类型
        $data['goods_id'] = $this['goods_id'];
        $data['spec_type'] = $this['spec_type'];
        // 创建秒杀商品数据
        $data = $this->createData($data, self::EVENT_EDIT);
        // 事务处理
        $this->transaction(function () use ($data) {
            // 更新商品
            $this->save($data);
            // 更新商品sku信息
            GoodsSkuModel::edit((int)$this['sharp_goods_id'], $this['spec_type'], $data['newSkuList']);
        });
        return true;
    }

    /**
     * 创建商品数据
     * @param array $data
     * @param string $event
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function createData(array $data, string $event = self::EVENT_ADD): array
    {
        // 默认数据
        $data = array_merge($data, [
            'newSkuList' => [],
            'store_id' => self::$storeId,
        ]);
        // 规格和sku数据处理
        $data['newSkuList'] = $this->getNewSkuList($data, $event);
        // 库存总量 seckill_stock
        // 商品价格 最低最高
        if ($data['spec_type'] == SpecTypeEnum::MULTI) {
            $data['seckill_stock'] = GoodsSkuModel::getStockTotal($data['newSkuList']);
            [$data['seckill_price_min'], $data['seckill_price_max']] = GoodsSkuModel::getGoodsPrices($data['newSkuList']);
        } elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
            $data['seckill_price_min'] = $data['seckill_price_max'] = $data['seckill_price'];
            // $data['seckill_stock'] = $data['seckill_stock'];
        }
        return $data;
    }

    /**
     * 生成新的SKU列表数据
     * @param array $data
     * @param string $event
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function getNewSkuList(array $data, string $event = self::EVENT_ADD): array
    {
        if ($event === self::EVENT_ADD) {
            // 生成默认的skuList
            if ($data['spec_type'] == SpecTypeEnum::MULTI) {
                return GoodsSkuModel::getDefaultSkuList($data['goods_id']);
            }
            return helper::pick($data, ['seckill_price', 'seckill_stock']);
        }
        return $this->getNewSkuListByEdit($data, $event);
    }

    /**
     * 生成新的SKU列表数据(用于编辑事件)
     * @param array $data
     * @param string $event
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function getNewSkuListByEdit(array $data, string $event = self::EVENT_ADD): array
    {
        // 规格和sku数据处理
        if ($data['spec_type'] == SpecTypeEnum::MULTI) {
            // 生成skuList ( 携带goods_sku_id )
            return GoodsSkuModel::getNewSkuList($data['goods_id'], $data['specData']['skuList']);
        } elseif ($data['spec_type'] == SpecTypeEnum::SINGLE) {
            // 生成skuItem
            return helper::pick($data, ['seckill_price', 'seckill_stock']);
        }
        return [];
    }

    /**
     * 验证主商品能否被添加为秒杀商品
     * @param int $goodsId 主商品ID
     * @return bool
     */
    private function validateGoodsId(int $goodsId): bool
    {
        if (empty($goodsId)) {
            $this->error = '很抱歉，您还没有选择商品';
            return false;
        }
        // 验证是否存在秒杀商品
        if ($this->isExistGoodsId($goodsId)) {
            $this->error = '很抱歉，该商品已存在，无需重复添加';
            return false;
        }
        return true;
    }

    /**
     * 验证指定商品是否已添加秒杀商品
     * @param int $goodsId 主商品ID
     * @return bool
     */
    public static function isExistGoodsId(int $goodsId): bool
    {
        return (bool)(new static)->where('goods_id', '=', $goodsId)
            ->where('is_delete', '=', 0)
            ->value('sharp_goods_id');
    }

    /**
     * 软删除
     * @return mixed
     */
    public function setDelete()
    {
        return $this->transaction(function () {
            // 同步删除活动会场与商品关联记录
            ActiveGoodsModel::deleteSharpGoods((int)$this['sharp_goods_id']);
            // 删除所有的sku记录
            GoodsSkuModel::deleteAll(['sharp_goods_id' => $this['sharp_goods_id']]);
            // 标记当前秒杀商品已删除
            return $this->save(['is_delete' => 1]);
        });
    }
}